package com.xlh.service.conclude.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.xlh.common.ResultEnum;
import com.xlh.constant.ConcludeContant;
import com.xlh.dao.conclude.ext.ConcludeStudentMapperExt;
import com.xlh.dao.conclude.helper.ConcludeMapperHelper;
import com.xlh.dao.conclude.helper.ConcludeStudentMapperHelper;
import com.xlh.dao.user.helper.ClassMapperHelper;
import com.xlh.dao.user.helper.UserClassMapperHelper;
import com.xlh.dao.user.helper.UserMapperHelper;
import com.xlh.dto.conclude.ConcludeParamDTO;
import com.xlh.dto.course.ClassZtreeDTO;
import com.xlh.exception.common.GlobalException;
import com.xlh.pojo.conclude.Conclude;
import com.xlh.pojo.conclude.ConcludeStudent;
import com.xlh.pojo.user.Class;
import com.xlh.pojo.user.User;
import com.xlh.pojo.user.UserClass;
import com.xlh.service.conclude.ConcludeStudentService;
import com.xlh.util.BeanUtil;
import com.xlh.util.ExcelsUtil;
import com.xlh.vo.conclude.ConCludeClassStudentVO;
import com.xlh.vo.conclude.StudentListInfoVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Service
public class ConcludeStudentServiceImpl implements ConcludeStudentService {

    @Autowired
    private ConcludeStudentMapperHelper concludeStudentMapperHelper;

    @Autowired
    private ConcludeStudentMapperExt concludeStudentMapperExt;

    @Autowired
    private UserClassMapperHelper userClassMapperHelper;

    @Autowired
    private UserMapperHelper userMapperHelper;

    @Autowired
    private ConcludeMapperHelper concludeMapperHelper;

    @Autowired
    private ClassMapperHelper classMapperHelper;



    @Override
    public PageInfo<StudentListInfoVO> list(Integer pageNum, Integer pageSize, Long concludeId, String className) {

        PageHelper.startPage(pageNum, pageSize);
        List<ConcludeStudent> students = concludeStudentMapperHelper.findByCondition(concludeId, className);
        PageInfo pageInfo = new PageInfo<>(students);
        List<StudentListInfoVO> studentListInfoVOS = BeanUtil.batchTransform(StudentListInfoVO.class, pageInfo.getList());
        for (int i = 1; i <= studentListInfoVOS.size(); i++) {
            studentListInfoVOS.get(i-1).setIndex(i);
        }
        pageInfo.setList(studentListInfoVOS);
        return pageInfo;
    }

    @Override
    public List<String> classList(Long concludeId , String className) {

        List<ConcludeStudent> concludeStudent = concludeStudentMapperHelper.findByCondition(concludeId, className);
        Map<String, List<String>> collect = concludeStudent.stream()
                                                           .map(ConcludeStudent::getClassName).collect(Collectors.groupingBy(name -> name));
        return new ArrayList(collect.keySet());
    }

    @Override
    public void update(StudentListInfoVO dto) {
        ConcludeStudent concludeStudents = BeanUtil.transform(ConcludeStudent.class, dto);
        // 原信息
        ConcludeStudent concludeStudent = concludeStudentMapperHelper.get(concludeStudents.getId());
        if(concludeStudent == null){
            throw new GlobalException(ResultEnum.NOT_FOUND_STUDENT_RECORD);
        }
        // 根据sno和condlueId值进行查询是否存在重复学号
        List<ConcludeStudent> isHaveRecordInfo = concludeStudentMapperHelper.findBySno(Lists.newArrayList(concludeStudents.getSno()), concludeStudent.getConcludeId());

        if(isHaveRecordInfo.size()>1){
            throw new GlobalException(ResultEnum.IS_EXIST_SNO);
        }
        if(CollectionUtil.isNotEmpty(isHaveRecordInfo)){
            ConcludeStudent existRecord = isHaveRecordInfo.get(0);
            if(existRecord.getId().compareTo(concludeStudents.getId()) != 0){
                throw new GlobalException(ResultEnum.IS_EXIST_SNO);
            }
        }
        concludeStudentMapperHelper.update(concludeStudents);
    }

    @Override
    public void delete(List<ConcludeParamDTO> stuIds) {

        concludeStudentMapperHelper.deleteBatchById(stuIds, null);
    }

    @Override
    public void importExcel(Long concludeId, MultipartFile file) {

        // 1. 从文件中获取数据
        InputStream inputStream = null;
        try{
            inputStream = file.getInputStream();
        }catch (Exception e){
            throw new GlobalException(ResultEnum.NOT_MATCH_TEMPLATE);
        }
        // 2.应用HUtool ExcelUtil获取ExcelReader指定输入流和sheet
        ExcelReader excelReader = ExcelUtil.getReader(inputStream, 0);
        // 可以加上表头验证
        List<Object> headerInfos = excelReader.readRow(2);
        if(headerInfos.size() != ConcludeContant.CONCLUDE_STUDENT_HEADER.size()){
            throw new GlobalException(ResultEnum.NOT_MATCH_TEMPLATE);
        }
        // 3.读取第二行到最后一行数据
        int index = 0;
        for (String key : ConcludeContant.CONCLUDE_STUDENT_HEADER.keySet()) {
            String header = headerInfos.get(index).toString().trim();
            if(!key.equals(header)){
                throw new GlobalException(ResultEnum.NOT_MATCH_TEMPLATE);
            }
            index++;
        }

        Conclude conclude = concludeMapperHelper.get(concludeId);
        if(ObjectUtil.isNull(conclude)){
            throw new GlobalException(ResultEnum.NOT_FOUND_CONCLUDE);
        }
        // 解析excel文件
        List<ConcludeStudent> excelParams = ExcelsUtil.readExcelData(
                file, ConcludeContant.CONCLUDE_STUDENT_HEADER , 2, 3, ConcludeStudent.class);
        // 放入concludeId
        Consumer<ConcludeStudent> consumer  = concludeStudent -> concludeStudent.setConcludeId(concludeId);
        excelParams.forEach(consumer);
        // 2.校验数据的合法性 后续用到再调用
        checkParam(excelParams);
        // 3. 过滤出合法参数
        excelParams = filter(excelParams);
        // 5. 执行批量插入
        if(CollectionUtil.isNotEmpty(excelParams)){
            insertOrUpdateRecord(excelParams);
        }
    }


    /**
     * 执行插入或者更新操作
     * @param excelParams 外部要导入到数据库的数据
     */
    private void insertOrUpdateRecord(List<ConcludeStudent> excelParams) {
        Long concludeId = excelParams.get(0).getConcludeId();
        List<String> snos = excelParams.stream().map(ConcludeStudent::getSno).collect(Collectors.toList());

        List<ConcludeStudent> alreadyExistRows = concludeStudentMapperHelper.findBySno( snos, concludeId );
        List<String> alreadyExistSon = alreadyExistRows.stream().map(ConcludeStudent::getSno).collect(Collectors.toList());

        Predicate<ConcludeStudent> predicate = concludeStudent -> {
            String sno = concludeStudent.getSno();
            if(alreadyExistSon.contains(sno))return false;
            return true;
        };
        Map<Boolean, List<ConcludeStudent>> collect = excelParams.stream().collect(Collectors.partitioningBy(predicate));

        if(CollectionUtil.isNotEmpty(collect.get(true))){
            concludeStudentMapperExt.insertBatch(collect.get(true));
        }
        // 6. 执行批量更新操作
        if(CollectionUtil.isNotEmpty(collect.get(false))){
            concludeStudentMapperHelper.updateBeach(collect.get(false));
        }
    }


    @Override
    public void classImport(List<Long> studentIds, Long concludeId, Long classId) {
        // 1. 根据班级ID查询所有学生信息
        Class aClass = classMapperHelper.get(classId);
        if(ObjectUtil.isNull(aClass)){
            throw new GlobalException(ResultEnum.NOT_FOUND_ClASS);
        }
        List<UserClass> userClassInfos = userClassMapperHelper.findByStudentIds(studentIds);
        List<Long> userIds = userClassInfos.stream().map(UserClass::getUserId).collect(Collectors.toList());
        // 2. 查询用户信息
        List<User> userInfos = userMapperHelper.findUserByIds(userIds);
        // 3. 查询表中的stuno信息
        List<ConcludeStudent> records = convertToConcludeStudent(userInfos, aClass.getName(), concludeId, userClassInfos);

        insertOrUpdateRecord(records);
        // 删除系统之前存留的学生信息
        List<ConcludeStudent> sysStudentInfos = concludeStudentMapperHelper.findSysStudentInfos(concludeId);

        List<ConcludeStudent> deleteRecords = sysStudentInfos.stream()
                            .filter(sysStudentInfo -> !studentIds.contains(sysStudentInfo.getSysStuId()))
                            .collect(Collectors.toList());
        List<ConcludeParamDTO> concludeParamDTOS = BeanUtil.batchTransform(ConcludeParamDTO.class, deleteRecords);
        if(CollectionUtil.isNotEmpty(concludeParamDTOS)){
            concludeStudentMapperHelper.deleteBatchById(concludeParamDTOS, aClass.getName());
        }

    }


    /**
     * 查询班级下的学生信息
     * @param classId
     * @param concludeId
     * @return
     */
    @Override
    public List<ConCludeClassStudentVO> classStudents(Long classId, Long concludeId) {

        List<UserClass> userClasses = userClassMapperHelper.findByCondition(classId);
        List<Long> userIds = userClasses.stream().map(UserClass::getUserId).collect(Collectors.toList());
        List<ConCludeClassStudentVO> conCludeClassStudentVOS = Lists.newArrayList();
        // 查询关联的学生信息
        if(CollectionUtil.isEmpty(userIds)){
            return conCludeClassStudentVOS;
        }
        List<User> usersInfo = userMapperHelper.findUserByIds(userIds);
        // 查询系统已导入的学生
        List<ConcludeStudent> existStudent = concludeStudentMapperHelper.findSysStudentInfos(concludeId);

        for (UserClass userClass : userClasses) {
            ConCludeClassStudentVO conCludeClassStudentVO = new ConCludeClassStudentVO();
            conCludeClassStudentVO.setSysStuId(userClass.getId());
            Long userId = userClass.getUserId();
            Optional<User> first = usersInfo.stream().filter(user -> user.getId().equals(userId)).findFirst();
            first.ifPresent( user -> conCludeClassStudentVO.setName(user.getName()));
            Boolean isExist = existStudent.stream().anyMatch(concludeStudent -> userClass.getId().equals(concludeStudent.getSysStuId()));
            conCludeClassStudentVO.setExist(isExist);
            conCludeClassStudentVOS.add(conCludeClassStudentVO);
        }
        return conCludeClassStudentVOS;
    }


    private List<ConcludeStudent> convertToConcludeStudent(List<User> userInfos, String className, Long concludeId, List<UserClass>  studentIds) {

        List<ConcludeStudent> students = Lists.newArrayList();
        for (User userInfo : userInfos) {
            ConcludeStudent student = new ConcludeStudent();
            Long userId = userInfo.getId();
            student.setClassName(className);
            student.setConcludeId(concludeId);
            student.setName(userInfo.getName());
            student.setSno(userInfo.getUserNumber());
            Optional<UserClass> first = studentIds.stream().filter(studentInfo -> studentInfo.getUserId().equals(userId)).findFirst();
            first.ifPresent(userClass ->  student.setSysStuId(userClass.getId()));
            students.add(student);
        }
        return students;
    }


    /**
     * 过滤非法数据
     * @param records
     * @return
     */
    private List<ConcludeStudent> filter(List<ConcludeStudent> records) {

        // 1. 过滤空值数据
        Predicate<ConcludeStudent> predicate = concludeStudent -> {
            // 班级名称为空
            if(StrUtil.isBlank(concludeStudent.getClassName()))return false;
            // 学生姓名为空
            if(StrUtil.isBlank(concludeStudent.getName()))return false;
            // 学生编号为空
            if(StrUtil.isBlank(concludeStudent.getSno()))return false;

            return true;
        };

        List<ConcludeStudent> collect = records.stream().filter(predicate).collect(Collectors.toList());
        // 2. 过滤重复的sno数据 取最后一条
        List<ConcludeStudent> result = Lists.newArrayList();
        Map<String, List<ConcludeStudent>> snoMap = collect.stream().collect(Collectors.groupingBy(ConcludeStudent::getSno));
        Collection<List<ConcludeStudent>> values = snoMap.values();
        for (List<ConcludeStudent> value : values) {
            ConcludeStudent concludeStudent = value.get(value.size()-1);
            result.add(concludeStudent);
        }

        return result;
    }

    /**
     * 校验数据的合法性
     * @param excelParams
     */
    private void checkParam(List<ConcludeStudent> excelParams) {

        for (int i = 0; i < excelParams.size(); i++) {

            String sno = excelParams.get(i).getSno();
            if( StrUtil.isBlank(sno) ){
                throw new GlobalException("存在学生学号为空！ 请检查excel");
            }
            String sname = excelParams.get(i).getName();
            if(StrUtil.isBlank(sname)){
                throw new GlobalException("存在学生姓名为空！请检查excel");
            }
            String className = excelParams.get(i).getClassName();
            if(StrUtil.isBlank(className)){
                throw new GlobalException("存在学生班级为空！请检查excel");
            }
        }

    }


}
